package data

import (
	"context"
	"time"

	"github.com/go-kratos/kratos/v2/log"

	"gitee.com/danqingzhao/go-dango/apps/user/biz"
	"gitee.com/danqingzhao/go-dango/apps/user/conf"
	"gitee.com/danqingzhao/go-dango/pkg/proto/auth"
	"gitee.com/danqingzhao/go-dango/pkg/proto/settings"
	"gitee.com/danqingzhao/go-dango/pkg/third/orm"
)

type roleRepo struct {
	data *Data
	log  *log.Helper
}

func NewRoleRepo(data *Data, logHelpers *settings.LogHelpers) biz.RoleRepo {
	return &roleRepo{data: data, log: logHelpers.Data}
}

func (r *roleRepo) CreateModel(ctx context.Context, m *biz.RoleModel) error {
	now := time.Now()
	m.CreatedAt = now
	m.UpdatedAt = now
	if err := orm.DBCreate(ctx, r.data.gormDB, &biz.RoleModel{}, m); err != nil {
		r.log.WithContext(ctx).Error(err.Error())
		return err
	}
	return nil
}

func (r *roleRepo) UpdateModel(ctx context.Context, m biz.RoleModel, upmap map[string]any, conds ...any) error {
	m.UpdatedAt = time.Now()
	if err := orm.DBUpdate(ctx, r.data.gormDB, &m, &biz.RoleModel{}, upmap, conds...); err != nil {
		r.log.WithContext(ctx).Error(err.Error())
		return err
	}
	return nil
}

func (r *roleRepo) DeleteModel(ctx context.Context, conds ...any) error {
	if err := orm.DBDelete(ctx, r.data.gormDB, &biz.RoleModel{}, conds...); err != nil {
		r.log.WithContext(ctx).Error(err.Error())
		return err
	}
	return nil
}

func (r *roleRepo) FindModel(
	ctx context.Context,
	preloads []string,
	conds ...any,
) (*biz.RoleModel, error) {
	var m biz.RoleModel
	if err := orm.DBFind(ctx, r.data.gormDB, preloads, &m, conds...); err != nil {
		r.log.WithContext(ctx).Error(err.Error())
		return nil, err
	}
	return &m, nil
}

func (r *roleRepo) ListModel(
	ctx context.Context,
	qp orm.QueryParams,
) (int64, []biz.RoleModel, error) {
	var ms []biz.RoleModel
	count, err := orm.DBList(ctx, r.data.gormDB, &biz.RoleModel{}, &ms, qp)
	if err != nil {
		r.log.WithContext(ctx).Error(err.Error())
		return 0, nil, err
	}
	return count, ms, nil
}

func (r *roleRepo) ListPolicies(ctx context.Context, m biz.RoleModel) ([][]string, [][]string) {
	sub := auth.PolicyRoleSub(conf.APPName, m.Id)
	pRules := make([][]string, len(m.Permissions))
	if len(pRules) > 0 {
		for i, perm := range m.Permissions {
			pRules[i] = []string{sub, perm.GrpcUrl, "GRPC"}
		}
	}
	num := len(m.Menus)
	gRules := make([][]string, num+len(m.Buttons))
	for i, menu := range m.Menus {
		gRules[i] = []string{sub, auth.PolicyMenuSub(conf.APPName, menu.Id)}
	}
	for i, button := range m.Buttons {
		gRules[i+num] = []string{sub, auth.PolicyButtonSub(conf.APPName, button.Id)}
	}
	return pRules, gRules
}
